bitkeeper revision 1.1159.99.1 (41614d0bCFm_w7iZTkZCC7k5oNSaqw)
authorcl349@freefall.cl.cam.ac.uk <cl349@freefall.cl.cam.ac.uk>
Mon, 4 Oct 2004 13:15:55 +0000 (13:15 +0000)
committercl349@freefall.cl.cam.ac.uk <cl349@freefall.cl.cam.ac.uk>
Mon, 4 Oct 2004 13:15:55 +0000 (13:15 +0000)
Cleanup device initialization.
Add support for bidirectional virtual consoles.

netbsd-2.0-xen-sparse/sys/arch/xen/i386/hypervisor_machdep.c
netbsd-2.0-xen-sparse/sys/arch/xen/include/if_xennetvar.h
netbsd-2.0-xen-sparse/sys/arch/xen/include/xbdvar.h
netbsd-2.0-xen-sparse/sys/arch/xen/xen/ctrl_if.c
netbsd-2.0-xen-sparse/sys/arch/xen/xen/hypervisor.c
netbsd-2.0-xen-sparse/sys/arch/xen/xen/if_xennet.c
netbsd-2.0-xen-sparse/sys/arch/xen/xen/xbd.c
netbsd-2.0-xen-sparse/sys/arch/xen/xen/xencons.c

index 82e998d3b6b87a7b18ae47ad3765c532c77bbc84..241a8a9b83f774f98cab4f8034250329c2fdf028 100644 (file)
@@ -127,8 +127,7 @@ stipending()
                                        hypervisor_acknowledge_irq(irq);
                                        ci->ci_ipending |= (1 << irq);
                                        if (ret == 0 && ci->ci_ilevel <
-                                           ci->ci_isources[irq]->is_handlers
-                                           ->ih_level)
+                                           ci->ci_isources[irq]->is_maxlevel)
                                                ret = 1;
                                }
 #if 0 /* XXXcl dev/evtchn */
index 32a774b1b6540dc3fe390ef295610045baeb2f31..5e84f5af8690742444ea632b4d55b501b0a27276 100644 (file)
@@ -81,6 +81,8 @@ struct xennet_softc {
 
        netif_tx_interface_t    *sc_tx;
        netif_rx_interface_t    *sc_rx;
+       struct vm_page          *sc_pg_tx;
+       struct vm_page          *sc_pg_rx;
 
        uint32_t                sc_tx_entries;
        uint32_t                sc_tx_resp_cons;
@@ -102,6 +104,7 @@ struct xennet_attach_args {
 struct nfs_diskless;
 
 int xennet_scan(struct device *, struct xennet_attach_args *, cfprint_t);
+void xennet_scan_finish(struct device *);
 void xennet_start(struct ifnet *);
 int xennet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
 void xennet_watchdog(struct ifnet *ifp);
index 8c1c57c692b383c2182a094ab9f872ffca0876fc..089d365a0dca915245e3a01369fbc188cf744202 100644 (file)
@@ -52,5 +52,6 @@ struct xbd_attach_args {
 };
 
 int xbd_scan(struct device *, struct xbd_attach_args *, cfprint_t);
+void xbd_scan_finish(struct device *);
 
 #endif /* _XEN_XBDVAR_H_ */
index 39b4febdd364c32c3a813b759c0b94a35e10ca21..d81068b0a111858d59f2afe622932415d7e9d60a 100644 (file)
@@ -20,8 +20,9 @@ __KERNEL_RCSID(0, "$NetBSD$");
 #include <machine/ctrl_if.h>
 #include <machine/evtchn.h>
 
+void printk(char *, ...);
 #if 0
-#define DPRINTK(_f, _a...) printf("(file=%s, line=%d) " _f, \
+#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \
                            __FILE__ , __LINE__ , ## _a )
 #else
 #define DPRINTK(_f, _a...) ((void)0)
@@ -34,7 +35,7 @@ __KERNEL_RCSID(0, "$NetBSD$");
  */
 int initdom_ctrlif_domcontroller_port = -1;
 
-static int ctrl_if_evtchn;
+/* static */ int ctrl_if_evtchn = -1;
 static int ctrl_if_irq;
 static struct simplelock ctrl_if_lock;
 
@@ -148,9 +149,10 @@ static void __ctrl_if_rxmsg_deferred(void *unused)
 
        while ( ctrl_if_rxmsg_deferred_cons != dp )
        {
-               msg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX(
-                                                     ctrl_if_rxmsg_deferred_cons++)];
+               msg = &ctrl_if_rxmsg_deferred[
+                   MASK_CONTROL_IDX(ctrl_if_rxmsg_deferred_cons)];
                (*ctrl_if_rxmsg_handler[msg->type])(msg, 0);
+               ctrl_if_rxmsg_deferred_cons++;
        }
 }
 
@@ -166,7 +168,7 @@ static void __ctrl_if_rx_tasklet(unsigned long data)
 
     while ( ctrl_if_rx_req_cons != rp )
     {
-        pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)];
+        pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons)];
         memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg));
 
         DPRINTK("Rx-Req %u/%u :: %d/%d\n", 
@@ -184,6 +186,8 @@ static void __ctrl_if_rx_tasklet(unsigned long data)
                    &msg, offsetof(ctrl_msg_t, msg) + msg.length);
         else
             (*ctrl_if_rxmsg_handler[msg.type])(&msg, 0);
+
+       ctrl_if_rx_req_cons++;
     }
 
     if ( dp != ctrl_if_rxmsg_deferred_prod )
@@ -205,11 +209,15 @@ static int ctrl_if_interrupt(void *arg)
 
     if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod ||
        ctrl_if_rx_req_cons != ctrl_if->rx_req_prod ) {
+#if 0
 #if 0
            wakeup(&ctrl_if_kthread);
 #else
            if (ctrl_if_softintr)
                    softintr_schedule(ctrl_if_softintr);
+#endif
+#else
+           ctrl_if_kthread((void *)1);
 #endif
     }
 
@@ -225,6 +233,7 @@ ctrl_if_send_message_noblock(
     control_if_t *ctrl_if = get_ctrl_if();
     unsigned long flags;
     int           i;
+    int s;
 
     save_and_cli(flags);
     simple_lock(&ctrl_if_lock);
@@ -233,7 +242,11 @@ ctrl_if_send_message_noblock(
     {
         simple_unlock(&ctrl_if_lock);
        restore_flags(flags);
-        return -EAGAIN;
+       s = splhigh();
+       if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod )
+               __ctrl_if_tx_tasklet(0);
+       splx(s);
+        return EAGAIN;
     }
 
     msg->id = 0xFF;
@@ -275,10 +288,13 @@ ctrl_if_send_message_block(
 
        while ((rc = ctrl_if_send_message_noblock(msg, hnd, id)) == EAGAIN) {
                /* XXXcl possible race -> add a lock and ltsleep */
+#if 1
+#else
                rc = tsleep((caddr_t) &ctrl_if_tx_wait, PUSER | PCATCH,
                    "ctrl_if", 0);
                if (rc)
                        break;
+#endif
        }
 
        return rc;
@@ -456,7 +472,6 @@ ctrl_if_kthread(void *arg)
 {
        control_if_t *ctrl_if = get_ctrl_if();
 
-       // printf("ctrl_if_kthread starting\n");
        for (;;) {
                if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod )
                        __ctrl_if_tx_tasklet(0);
@@ -464,10 +479,6 @@ ctrl_if_kthread(void *arg)
                if ( ctrl_if_rx_req_cons != ctrl_if->rx_req_prod )
                        __ctrl_if_rx_tasklet(0);
 
-               if ( ctrl_if_rxmsg_deferred_cons !=
-                   ctrl_if_rxmsg_deferred_prod )
-                       __ctrl_if_rxmsg_deferred(NULL);
-
                if (arg) {
                        // printf("ctrl_if_kthread one-shot done\n");
                        return;
@@ -479,13 +490,19 @@ ctrl_if_kthread(void *arg)
 }
 
 static void
-ctrl_if_create_kthread(void *arg)
+ctrl_if_softintr_handler(void *arg)
 {
+       static int in_handler = 0;
 
-       printf("ctrl_if_kthread creating\n");
-       if (kthread_create1(ctrl_if_kthread, arg, NULL, "ctrl_if"))
-               printf("ctrl_if_kthread create failed\n");
-       softintr_schedule(ctrl_if_softintr);
+       if (in_handler++ != 0) {
+               ctrl_if_evtchn = -1;
+               panic("recurse");
+       }
+
+       if ( ctrl_if_rxmsg_deferred_cons != ctrl_if_rxmsg_deferred_prod )
+               __ctrl_if_rxmsg_deferred(NULL);
+
+       in_handler--;
 }
 
 #ifdef notyet
@@ -528,20 +545,29 @@ void ctrl_if_resume(void)
     hypervisor_enable_irq(ctrl_if_irq);
 }
 
+void ctrl_if_early_init(void);
+void ctrl_if_early_init(void)
+{
+
+       simple_lock_init(&ctrl_if_lock);
+
+       ctrl_if_evtchn = xen_start_info.domain_controller_evtchn;
+}
+
 void ctrl_if_init(void)
 {
-        int i;
+       int i;
 
-    for ( i = 0; i < 256; i++ )
-        ctrl_if_rxmsg_handler[i] = ctrl_if_rxmsg_default_handler;
+       for ( i = 0; i < 256; i++ )
+               ctrl_if_rxmsg_handler[i] = ctrl_if_rxmsg_default_handler;
 
-    simple_lock_init(&ctrl_if_lock);
+       if (ctrl_if_evtchn == -1)
+               ctrl_if_early_init();
 
-    if (0) kthread_create(ctrl_if_create_kthread, NULL);
-    ctrl_if_softintr =
-           softintr_establish(IPL_SOFTNET, ctrl_if_kthread, (void *)1);
+       ctrl_if_softintr = softintr_establish(IPL_SOFTNET,
+           ctrl_if_softintr_handler, NULL);
 
-    ctrl_if_resume();
+       ctrl_if_resume();
 }
 
 
index 0f5a9fe788863f87116ee8a98e1700f46ae89e5c..294f79830a7ea37599bfec4d0c0831929773335f 100644 (file)
@@ -133,6 +133,18 @@ hypervisor_match(parent, match, aux)
        return 0;
 }
 
+static void
+scan_finish(struct device *parent)
+{
+
+#if NXENNET > 0
+       xennet_scan_finish(parent);
+#endif
+#if NXBD > 0
+       xbd_scan_finish(parent);
+#endif
+}
+
 /*
  * Attach the hypervisor.
  */
@@ -183,6 +195,9 @@ hypervisor_attach(parent, self, aux)
                xenvfr_init();
        }
 #endif
+#if NXENNET > 0 || NXBD > 0
+       config_interrupts(self, scan_finish);
+#endif
 }
 
 int
index a48f854f13fbfba7c0153fb06ac809e412485dc8..1670da4ea392b35d89af31c212975a90a8e6555d 100644 (file)
@@ -106,8 +106,9 @@ __KERNEL_RCSID(0, "$NetBSD: if_xennet.c,v 1.1.2.1 2004/05/22 15:58:29 he Exp $")
 #define XEDB_MBUF      0x08
 #define XEDB_MEM       0x10
 int xennet_debug = 0x0;
-#define DPRINTF(x) if (xennet_debug) printf x;
-#define DPRINTFN(n,x) if (xennet_debug & (n)) printf x;
+void printk(char *, ...);
+#define DPRINTF(x) if (xennet_debug) printk x;
+#define DPRINTFN(n,x) if (xennet_debug & (n)) printk x;
 #else
 #define DPRINTF(x)
 #define DPRINTFN(n,x)
@@ -174,13 +175,21 @@ static int nxennet_media = (sizeof(xennet_media)/sizeof(xennet_media[0]));
 #endif
 
 
+static int
+xennet_wait_for_interfaces(void)
+{
+
+       while (netctrl.xc_interfaces != netctrl.xc_connected)
+               HYPERVISOR_yield();
+       return 0;
+}
+
 int
 xennet_scan(struct device *self, struct xennet_attach_args *xneta,
     cfprint_t print)
 {
        ctrl_msg_t cmsg;
        netif_fe_driver_status_t st;
-       int err = 0;
 
        if ((xen_start_info.flags & SIF_INITDOMAIN) ||
            (xen_start_info.flags & SIF_NET_BE_DOMAIN))
@@ -203,13 +212,17 @@ xennet_scan(struct device *self, struct xennet_attach_args *xneta,
        memcpy(cmsg.msg, &st, sizeof(st));
        ctrl_if_send_message_block(&cmsg, NULL, 0, 0);
 
-#if 0
+       return 0;
+}
+
+void
+xennet_scan_finish(struct device *parent)
+{
+       int err;
+
        err = xennet_wait_for_interfaces();
        if (err)
                ctrl_if_unregister_receiver(CMSG_NETIF_FE, xennet_ctrlif_rx);
-#endif
-
-       return err;
 }
 
 int
@@ -270,7 +283,7 @@ find_device(int handle)
                if (xs->sc_ifno == handle)
                        break;
        }
-       return xs;
+       return dv ? xs : NULL;
 }
 
 static void
@@ -278,6 +291,7 @@ xennet_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
 {
        int respond = 1;
 
+       DPRINTFN(XEDB_EVENT, ("> ctrlif_rx=%d\n", msg->subtype));
        switch (msg->subtype) {
        case CMSG_NETIF_FE_INTERFACE_STATUS:
                if (msg->length != sizeof(netif_fe_interface_status_t))
@@ -307,7 +321,8 @@ static void
 xennet_driver_status_change(netif_fe_driver_status_t *status)
 {
 
-       DPRINTFN(XEDB_EVENT, ("> status=%d\n", status->status));
+       DPRINTFN(XEDB_EVENT, ("xennet_driver_status_change(%d)\n",
+                    status->status));
 
        netctrl.xc_up = status->status;
        xennet_driver_count_connected();
@@ -340,10 +355,9 @@ xennet_interface_status_change(netif_fe_interface_status_t *status)
        netif_fe_interface_connect_t up;
        struct xennet_softc *sc;
        struct ifnet *ifp;
-       struct vm_page *pg_tx, *pg_rx;
        struct xennet_attach_args xneta;
 
-       DPRINTFN(XEDB_EVENT, ("> status=%d handle=%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
+       DPRINTFN(XEDB_EVENT, ("xennet_interface_status_change(%d,%d,%02x:%02x:%02x:%02x:%02x:%02x)\n",
            status->status,
            status->handle,
            status->mac[0], status->mac[1], status->mac[2],
@@ -363,6 +377,11 @@ xennet_interface_status_change(netif_fe_interface_status_t *status)
        }
        ifp = &sc->sc_ethercom.ec_if;
 
+       DPRINTFN(XEDB_EVENT, ("xennet_interface_status_change(%d,%p,%02x:%02x:%02x:%02x:%02x:%02x)\n",
+                    status->handle, sc,
+                    status->mac[0], status->mac[1], status->mac[2],
+                    status->mac[3], status->mac[4], status->mac[5]));
+
        switch (status->status) {
        case NETIF_INTERFACE_STATUS_CLOSED:
                printf("Unexpected netif-CLOSED message in state %d\n",
@@ -411,28 +430,30 @@ xennet_interface_status_change(netif_fe_interface_status_t *status)
                }
 #endif
 
-               /* Move from CLOSED to DISCONNECTED state. */
-               sc->sc_tx = (netif_tx_interface_t *)
-                       uvm_km_valloc_align(kernel_map, PAGE_SIZE, PAGE_SIZE);
-               if (sc->sc_tx == NULL)
-                       panic("netif: no tx va");
-               sc->sc_rx = (netif_rx_interface_t *)
-                       uvm_km_valloc_align(kernel_map, PAGE_SIZE, PAGE_SIZE);
-               if (sc->sc_rx == NULL)
-                       panic("netif: no rx va");
-               pg_tx = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
-               if (pg_tx == NULL) {
-                       panic("netif: no tx pages");
-               }
-               pmap_kenter_pa((vaddr_t)sc->sc_tx, VM_PAGE_TO_PHYS(pg_tx),
-                   VM_PROT_READ | VM_PROT_WRITE);
-               pg_rx = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
-               if (pg_rx == NULL) {
-                       panic("netif: no rx pages");
+               if (sc->sc_backend_state == BEST_CLOSED) {
+                       /* Move from CLOSED to DISCONNECTED state. */
+                       sc->sc_tx = (netif_tx_interface_t *)
+                               uvm_km_valloc_align(kernel_map, PAGE_SIZE, PAGE_SIZE);
+                       if (sc->sc_tx == NULL)
+                               panic("netif: no tx va");
+                       sc->sc_rx = (netif_rx_interface_t *)
+                               uvm_km_valloc_align(kernel_map, PAGE_SIZE, PAGE_SIZE);
+                       if (sc->sc_rx == NULL)
+                               panic("netif: no rx va");
+                       sc->sc_pg_tx = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
+                       if (sc->sc_pg_tx == NULL) {
+                               panic("netif: no tx pages");
+                       }
+                       pmap_kenter_pa((vaddr_t)sc->sc_tx, VM_PAGE_TO_PHYS(sc->sc_pg_tx),
+                           VM_PROT_READ | VM_PROT_WRITE);
+                       sc->sc_pg_rx = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
+                       if (sc->sc_pg_rx == NULL) {
+                               panic("netif: no rx pages");
+                       }
+                       pmap_kenter_pa((vaddr_t)sc->sc_rx, VM_PAGE_TO_PHYS(sc->sc_pg_rx),
+                           VM_PROT_READ | VM_PROT_WRITE);
+                       sc->sc_backend_state = BEST_DISCONNECTED;
                }
-               pmap_kenter_pa((vaddr_t)sc->sc_rx, VM_PAGE_TO_PHYS(pg_rx),
-                   VM_PROT_READ | VM_PROT_WRITE);
-               sc->sc_backend_state = BEST_DISCONNECTED;
 
                /* Construct an interface-CONNECT message for the
                 * domain controller. */
@@ -440,8 +461,8 @@ xennet_interface_status_change(netif_fe_interface_status_t *status)
                cmsg.subtype   = CMSG_NETIF_FE_INTERFACE_CONNECT;
                cmsg.length    = sizeof(netif_fe_interface_connect_t);
                up.handle      = status->handle;
-               up.tx_shmem_frame = xpmap_ptom(VM_PAGE_TO_PHYS(pg_tx)) >> PAGE_SHIFT;
-               up.rx_shmem_frame = xpmap_ptom(VM_PAGE_TO_PHYS(pg_rx)) >> PAGE_SHIFT;
+               up.tx_shmem_frame = xpmap_ptom(VM_PAGE_TO_PHYS(sc->sc_pg_tx)) >> PAGE_SHIFT;
+               up.rx_shmem_frame = xpmap_ptom(VM_PAGE_TO_PHYS(sc->sc_pg_rx)) >> PAGE_SHIFT;
                memcpy(cmsg.msg, &up, sizeof(up));
 
                /* Tell the controller to bring up the interface. */
@@ -514,6 +535,7 @@ xennet_interface_status_change(netif_fe_interface_status_t *status)
                    status->status);
                break;
        }
+       DPRINTFN(XEDB_EVENT, ("xennet_interface_status_change()\n"));
 }
 
 static void
@@ -806,8 +828,6 @@ network_alloc_rx_buffers(struct xennet_softc *sc)
        int s;
 
        ringidx = sc->sc_rx->req_prod;
-       if (0) printf("network_alloc_rx_buffers prod %d cons %d\n", ringidx,
-           sc->sc_rx_resp_cons);
        if ((ringidx - sc->sc_rx_resp_cons) > (RX_MAX_ENTRIES / 2))
                return;
 
index 9cfab063a97e74df6cea7a7ecd82cabafec74ed9..a8034a211620383bdb0dc8fb733663a5a4d89f70 100644 (file)
@@ -809,7 +809,7 @@ send_driver_status(int ok)
                .subtype = CMSG_BLKIF_FE_DRIVER_STATUS,
                .length  = sizeof(blkif_fe_driver_status_t),
        };
-       blkif_fe_driver_status_t *msg = (void*)cmsg.msg;
+       blkif_fe_driver_status_t *msg = (blkif_fe_driver_status_t *)cmsg.msg;
     
        msg->status = ok ? BLKIF_DRIVER_STATUS_UP : BLKIF_DRIVER_STATUS_DOWN;
 
@@ -825,7 +825,8 @@ send_interface_connect(void)
                .subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
                .length  = sizeof(blkif_fe_interface_connect_t),
        };
-       blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
+       blkif_fe_interface_connect_t *msg =
+               (blkif_fe_interface_connect_t *)cmsg.msg;
        paddr_t pa;
 
        pmap_extract(pmap_kernel(), (vaddr_t)blk_ring, &pa);
@@ -866,6 +867,15 @@ setup_sysctl(void)
                diskcookies = pnode;
 }
 
+static int
+xbd_wait_for_interfaces(void)
+{
+
+       while (state != STATE_CONNECTED)
+               HYPERVISOR_yield();
+       return 0;
+}
+
 int
 xbd_scan(struct device *self, struct xbd_attach_args *mainbus_xbda,
     cfprint_t print)
@@ -912,13 +922,19 @@ xbd_scan(struct device *self, struct xbd_attach_args *mainbus_xbda,
 
        send_driver_status(1);
 
-#if 0
-       enable_update_events(self);
-#endif
-
        return 0;
 }
 
+void
+xbd_scan_finish(struct device *parent)
+{
+       int err;
+
+       err = xbd_wait_for_interfaces();
+       if (err)
+               ctrl_if_unregister_receiver(CMSG_NETIF_FE, xbd_ctrlif_rx);
+}
+
 #if NXBD > 0
 int
 xbd_match(struct device *parent, struct cfdata *match, void *aux)
index a151e3dd830f35919c61618f1b08dcded1c58b7a..91fbccd9ed02fdd77e72f118b15e794e7302cde1 100644 (file)
@@ -46,6 +46,8 @@ __KERNEL_RCSID(0, "$NetBSD: xencons.c,v 1.1.2.1 2004/05/22 15:59:21 he Exp $");
 #include <machine/stdarg.h>
 #include <machine/xen.h>
 #include <machine/hypervisor.h>
+#include <machine/evtchn.h>
+#include <machine/ctrl_if.h>
 
 #include <dev/cons.h>
 
@@ -87,6 +89,7 @@ const struct cdevsw xencons_cdevsw = {
 };
 
 
+static void xencons_rx(ctrl_msg_t *, unsigned long);
 void xenconscn_attach(void);
 int xenconscn_getc(dev_t);
 void xenconscn_putc(dev_t, int);
@@ -131,6 +134,8 @@ xencons_attach(struct device *parent, struct device *self, void *aux)
 
                /* Set db_max_line to avoid paging. */
                db_max_line = 0x7fffffff;
+
+               (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
        }
 }
 
@@ -258,7 +263,6 @@ xencons_start(struct tty *tp)
 {
        struct clist *cl;
        int s, len;
-       u_char buf[XENCONS_BURST+1];
 
        s = spltty();
        if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
@@ -271,8 +275,22 @@ xencons_start(struct tty *tp)
         * expensive and we don't want our serial ports to overflow.
         */
        cl = &tp->t_outq;
-       len = q_to_b(cl, buf, XENCONS_BURST);
-       (void)HYPERVISOR_console_io(CONSOLEIO_write, len, buf);
+       if (xen_start_info.flags & SIF_INITDOMAIN) {
+               u_char buf[XENCONS_BURST+1];
+
+               len = q_to_b(cl, buf, XENCONS_BURST);
+               (void)HYPERVISOR_console_io(CONSOLEIO_write, len, buf);
+       } else {
+               ctrl_msg_t msg;
+
+               len = q_to_b(cl, msg.msg, sizeof(msg.msg));
+               msg.type = CMSG_CONSOLE;
+               msg.subtype = CMSG_CONSOLE_DATA;
+               msg.length = len;
+               ctrl_if_send_message_noblock(&msg, NULL, 0);
+               /* XXX check return value and queue wait for space
+                * thread/softint */
+       }
 
        s = spltty();
        tp->t_state &= ~TS_BUSY;
@@ -298,13 +316,47 @@ xencons_stop(struct tty *tp, int flag)
 }
 
 
+/* Non-privileged receive callback. */
+static void
+xencons_rx(ctrl_msg_t *msg, unsigned long id)
+{
+       int i;
+       int s;
+       // unsigned long flags;
+       struct xencons_softc *sc;
+       struct tty *tp;
+
+       sc = device_lookup(&xencons_cd, XENCONS_UNIT(cn_tab->cn_dev));
+       if (sc == NULL)
+               goto out;
+
+       tp = sc->sc_tty;
+       if (tp == NULL)
+               goto out;
+
+       s = spltty();
+       // save_and_cli(flags);
+       // simple_lock(&xencons_lock);
+       for (i = 0; i < msg->length; i++)
+               (*tp->t_linesw->l_rint)(msg->msg[i], tp);
+       // simple_unlock(&xencons_lock);
+       // restore_flags(flags);
+       splx(s);
 
+ out:
+       msg->length = 0;
+       ctrl_if_send_response(msg);
+}
+
+void ctrl_if_early_init(void);
 void
 xenconscn_attach()
 {
 
        cn_tab = &xencons;
 
+       ctrl_if_early_init();
+
        xencons_isconsole = 1;
 }
 
@@ -316,18 +368,29 @@ xenconscn_getc(dev_t dev)
        for (;;);
 }
 
-#define MAXLINELEN 1024
 void
 xenconscn_putc(dev_t dev, int c)
 {
-       static char buf[1024+1];
-       static int bufpos = 0;
-
-       buf[bufpos++] = c;
-       if (c == '\n') {
-               buf[bufpos] = 0;
-               (void)HYPERVISOR_console_io(CONSOLEIO_write, bufpos, buf);
-               bufpos = 0;
+       extern int ctrl_if_evtchn;
+
+       if (xen_start_info.flags & SIF_INITDOMAIN ||
+               ctrl_if_evtchn == -1) {
+               u_char buf[1];
+
+               buf[0] = c;
+               (void)HYPERVISOR_console_io(CONSOLEIO_write, 1, buf);
+       } else {
+               ctrl_msg_t msg;
+
+               msg.type = CMSG_CONSOLE;
+               msg.subtype = CMSG_CONSOLE_DATA;
+               msg.length = 1;
+               msg.msg[0] = c;
+               while (ctrl_if_send_message_noblock(&msg, NULL, 0) == EAGAIN) {
+                       HYPERVISOR_yield();
+                       /* XXX check return value and queue wait for space
+                        * thread/softint */
+               }
        }
 }